音频组件初始化&进度条状态控制
概述
本节实现进度条的 seek 跳转功能:用户拖动进度条时音频跳转到对应位置播放,包括播放中跳转和暂停状态下跳转的逻辑处理。
进度条跳转(Seek)实现
Howler.js seek 方法
// seek() 两种用法:
// 1. 获取当前播放位置(秒)
const currentPos = audioInstance.value.seek()
// 2. 跳转到指定位置(秒)
audioInstance.value.seek(30) // 跳到 30 秒处
audioInstance.value.seek(30, id) // 指定 soundId
typescript
Watch 监听进度变化
import { watch } from 'vue'
// 监听 progress 百分比变化
watch(progressPercent, (newVal) => {
if (!audioInstance.value) return
// 将百分比转换为秒数并 seek
const seekSeconds = newVal * state.duration
audioInstance.value.seek(seekSeconds)
// 立即更新进度显示(不论是否在播放)
state.progress = newVal * state.duration
})
typescript
完整的进度条控制逻辑
const progressPercent = computed({
get: () => state.duration > 0 ? state.progress / state.duration : 0,
set: (val: number) => {
// 立即更新显示状态(暂停时也能看到进度变化)
state.progress = val * state.duration
// 如果音频实例存在,执行 seek
if (audioInstance.value) {
audioInstance.value.seek(val * state.duration)
}
}
})
typescript
步进控制(前进/后退 15 秒)
const STEP_SECONDS = 15
function handleForward() {
const currentPos = audioInstance.value?.seek() as number || 0
const newPos = Math.min(currentPos + STEP_SECONDS, state.duration)
audioInstance.value?.seek(newPos)
state.progress = newPos
}
function handleBackward() {
const currentPos = audioInstance.value?.seek() as number || 0
const newPos = Math.max(currentPos - STEP_SECONDS, 0)
audioInstance.value?.seek(newPos)
state.progress = newPos
}
typescript
状态同步问题与修复
问题:暂停状态下拖拽进度条时间不更新
原因:播放时进度条通过 requestAnimationFrame 定时器更新,暂停后定时器停止,seek 后时间显示不刷新。
修复:在进度条变化时立即同步更新 state.progress,不依赖定时器:
// 修复前:只在播放时更新(暂停时不更新)
watch(progressPercent, (newVal) => {
if (audioInstance.value) {
audioInstance.value.seek(newVal * state.duration)
}
// ❌ 缺少 state.progress 的即时更新
})
// 修复后:始终立即更新
watch(progressPercent, (newVal) => {
if (audioInstance.value) {
audioInstance.value.seek(newVal * state.duration)
}
// ✅ 无论播放/暂停都立即更新进度
state.progress = newVal * state.duration
})
typescript
进度条与时间显示联动
// 格式化时间显示
const currentTimeDisplay = computed(() => formatTime(state.progress))
const durationDisplay = computed(() => formatTime(state.duration))
function formatTime(seconds: number): string {
if (!seconds || isNaN(seconds)) return '00:00'
const mins = Math.floor(seconds / 60)
const secs = Math.floor(seconds % 60)
return `${String(mins).padStart(2, '0')}:${String(secs).padStart(2, '0')}`
}
typescript
完整控制方法汇总
| 操作 | 方法 | API 调用 |
|---|---|---|
| 拖拽进度条 | progressPercent setter | seek(seconds) |
| 前进 15 秒 | handleForward() | seek(current + 15) |
| 后退 15 秒 | handleBackward() | seek(current - 15) |
| 播放/暂停 | togglePlay() | play() / pause() |
| 音量调节 | applyVolume() | volume(val) |
| 速率调节 | applyRate() | rate(val) |
小结
- 进度条跳转通过
Howl.seek(seconds)实现,接收秒数参数 - 暂停状态下拖拽进度条需要立即更新
state.progress,不能依赖播放定时器 - 步进控制(前进/后退)通过
seek(current ± 15)实现 - 使用
computed的 setter 实现进度条双向绑定,保证显示与实际播放位置同步
↑